﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Dycox.Reporting.Aggregation
{
    internal abstract class ArithmeticalAggregationContext : AggregationContext
    {
        public ArithmeticalAggregationContext(string dataMember)
            : base(dataMember)
        {

        }

        protected override void Aggregate(object value, object dataObject, System.ComponentModel.PropertyDescriptor property)
        {
            decimal? dec;

            if (value != null)
            {
                IConvertible c = value as IConvertible;

                if (c == null)
                    throw new InvalidOperationException("");
                dec = c.ToDecimal(System.Globalization.CultureInfo.CurrentCulture);
            }
            else
                dec = null;

            Aggregate(dec);
        }

        protected abstract void Aggregate(decimal? number);

    }

    internal class Sum : ArithmeticalAggregationContext
    {
        public Sum(string dataMember)
            : base(dataMember)
        {

        }

        decimal _total;

        protected override void Initialize()
        {
            base.Initialize();

            _total = decimal.Zero;
        }

        protected override void Aggregate(decimal? number)
        {
            if (number.HasValue)
                _total += number.Value;
        }

        protected override object FinishAggregate()
        {
            return _total;
        }
    }

    internal class Average : Sum
    {
        public Average(string dataMember)
            : base(dataMember)
        {

        }

        private bool _countNullValues;

        public bool CountNullValues
        {
            get { return _countNullValues; }
            set { _countNullValues = value; }
        }

        int _count;

        protected override void Initialize()
        {
            base.Initialize();

            _count = 0;
        }

        protected override void Aggregate(decimal? number)
        {
            base.Aggregate(number);

            if (number.HasValue || _countNullValues)
                _count++;
        }

        protected override object FinishAggregate()
        {
            decimal total = (decimal)base.FinishAggregate();

            if (_count > 0) return total / _count;
            else return null;
        }
    }
}
